/*
Copyright (C) 2012 Brady Vidovic

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package ftr.gson;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
import java.lang.reflect.Type;
import java.util.Arrays;
import static btv.tools.BTVConstants.*;

/**
 * 
 * @author Brady Vidovic
 */
public class Serializers {
    
    
    public static final FTRDateDeserializer FTR_DATE_DE_SERIALIZER = new FTRDateDeserializer();    
    public static final FTRDateSerializer FTR_DATE_SERIALIZER = new FTRDateSerializer();
    
    
    private static class FTRDateSerializer implements JsonSerializer<FTRDate> 
    {

        @Override
        public JsonElement serialize(FTRDate src, Type typeOfSrc, JsonSerializationContext context) {
            return src == null ? null : new JsonPrimitive(src.toString());
        }
        
    }
    
    private static class FTRDateDeserializer implements JsonDeserializer<FTRDate> 
    {
      public FTRDate deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)throws JsonParseException 
      {                               
          if(json == null) return null;                        
                    
          String ftrDate = json.getAsString();//Like: /Date(1328882956000-0600)/
          /*Details on the format:
            DateTime Wire Format

            DateTime values appear as JSON strings in the form of "/Date(700000+0500)/", where the first number (700000 in the example provided) 
            is the number of milliseconds in the GMT time zone, regular (non-daylight savings) time since midnight, January 1, 1970. The number 
            may be negative to represent earlier times. The part that consists of "+0500" in the example is optional and indicates that the time 
            is of the Local kind - that is, should be converted to the local time zone on deserialization. If it is absent, the time is 
            deserialized as Utc. The actual number ("0500" in this example) and its sign (+ or -) are ignored.

            When serializing DateTime, Local and Unspecified times are written with an offset, and Utc is written without.

            The ASP.NET AJAX client JavaScript code automatically converts such strings into JavaScript DateTime instances. If there are other 
            strings that have a similar form that are not of type DateTime in .NET, they are converted as well.

            The conversion only takes place if the "/" characters are escaped (that is, the JSON looks like "\/Date(700000+0500)\/"), and for 
            this reason WCF's JSON encoder (enabled by the WebHttpBinding) always escapes the "/" character.
           */
          
          //we just need the milliseconds, they represent standard GMT ms.          
          
          if(ftrDate == null) return null;
          try
          {                            
              //parse unix epoch milliseconds from the string
              int start = ftrDate.indexOf("(")+1;              
              if(start == -1)//timezone is not specified (it is optional)
                  throw new Exception("No start delimiter found '(' in \""+ftrDate+"\"");
              
              //the timezone is optional. So look for +- first, then the closing ) last
              String[] possibleEndChars = new String[]{"-","+",")"};
              int end = -1;
              for(String endChar : possibleEndChars)
              {
                  end = ftrDate.indexOf(endChar);
                  if(end != -1) break;//found char
              }
                                              
              if(end == -1)//timezone is not specified (it is optional)
                  throw new Exception("No end delimiter found "+Arrays.toString(possibleEndChars)+" in \""+ftrDate+"\"");
              
              String ms = ftrDate.substring(start,end);              
              return new FTRDate(Long.parseLong(ms));
          }
          catch(Exception x)
          {
              Logger.ERROR("Failed to parse FTRDate: \""+ftrDate+"\". "
                      + "Expected format is: \"/Date(milliseconds-timezone)/\"");
              return null;
          }                                          
        }
    }    
}
